import au.edu.thinkinghead.synapse.*;
import java.lang.*;

public class S4JApp {

	public static void main(String[] args) {
		
		// need to load the Synapse native module
		try {
			//System.loadLibrary("Synapse4Java"); // assumes "Synapse4Java.dll" to be present in class directory
			System.loadLibrary("Synapse4Java64"); // for 64-bit VMs
		} catch (UnsatisfiedLinkError e) {
			System.err.println("Synapse native code library failed to load.\n" + e);
			System.err.println("LIBPATH:  {" + System.getProperty("java.library.path")+"}");
			System.exit(1);
		}
				
		// Example 1: A Synapse storing an array of floats
		FloatSynapse myFloats = new FloatSynapse();
		myFloats.Create("Shared_Floats_Name", 10); // create float array, size 10
		myFloats.Write(9); // write the value 9 into the first array element
		myFloats.Write(3.5f, 4); // write the value 3.5 into the 5th array element
		
		FloatSynapse yourFloats = new FloatSynapse();
		yourFloats.Open("Shared_Floats_Name"); // open above float array
		float[] localArray = new float[5];
		yourFloats.ReadArray(localArray, 5); // read first five elements of shared float array into local array
		for (int i = 0; i < 5; i++) { System.out.print(localArray[i] + " "); }
		System.out.println();
		
		myFloats.Release(); // should close Synapse once done with it (but not required)
		yourFloats.Release();
		
		// Example 2: A Synapse storing a string
		StringSynapse myString = new StringSynapse(); // CharSynapse with special Java-String helper methods
		myString.Create("Shared_String_Name", 20);
		myString.WriteString("I am legend.");
		
		StringSynapse yourString = new StringSynapse();
		yourString.Open("Shared_String_Name");
		String localString = yourString.ReadString();
		System.out.println(localString);
		
		myString.Release();
		yourString.Release();
		
		// Example 3: Send a message to Head X (if running).
	    if (Int32Synapse.Exists("Head-X"))
	    {
		   Int32Synapse myHeadVersion = new Int32Synapse();
		   myHeadVersion.Open("Head-X(1)");
		   System.out.println("Head X detected: version " + myHeadVersion.ReadCopy());

		   Int32Synapse myHeadStatus = new Int32Synapse();
           myHeadStatus.Open("Head-X(1)-Status");
           myHeadStatus.SetAsRead(); // so that IsNew() will work below

           StringSynapse myHeadCommand = new StringSynapse();
		   myHeadCommand.Open("Head-X(1)-Command");
		   myHeadCommand.ProtectWriteString("Hello user. I am connected through Java Synapse.");
		   
           System.out.print("Speaking");
           myHeadStatus.WaitForNew(); // wait for the head to start speaking
           while (myHeadStatus.ReadCopy(1) > 0)
           {
               System.out.print(".");
               try {
			      Thread.sleep(250);
			   } catch (InterruptedException e) {
			      Thread.currentThread().interrupt();
			   }
           }
           System.out.println();
           System.out.println("Done speaking.");
        }
	    else
	    {
           System.out.println("No Head X instance detected.\n");
	    }
	    
	    // Example 4: A Synchrony ring buffer.
        ByteSynchrony myBuffer = new ByteSynchrony();
        myBuffer.SetBufferSize(1000);
        myBuffer.Create("Synchrony_Buffer");
        ByteSynchroSample bsWrite = new ByteSynchroSample();
        short[] byteArray = {1,2,3};
        bsWrite.SetAllData(byteArray, byteArray.length);
        myBuffer.Push(bsWrite);

        ByteSynchrony yourBuffer = new ByteSynchrony();
        yourBuffer.Open("Synchrony_Buffer");
        ByteSynchroSample bsRead = myBuffer.ReadNewest();
        System.out.println("Buffer contents: " + bsRead.GetData(0) + bsRead.GetData(1) + bsRead.GetData(2));
	}

}